LCOV - code coverage report
Current view: top level - src/eap_peer - eap_leap.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 11 211 5.2 %
Date: 2014-03-02 Functions: 1 9 11.1 %
Branches: 2 78 2.6 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * EAP peer method: LEAP
       3                 :            :  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
       4                 :            :  *
       5                 :            :  * This software may be distributed under the terms of the BSD license.
       6                 :            :  * See README for more details.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include "includes.h"
      10                 :            : 
      11                 :            : #include "common.h"
      12                 :            : #include "crypto/ms_funcs.h"
      13                 :            : #include "crypto/crypto.h"
      14                 :            : #include "crypto/random.h"
      15                 :            : #include "eap_i.h"
      16                 :            : 
      17                 :            : #define LEAP_VERSION 1
      18                 :            : #define LEAP_CHALLENGE_LEN 8
      19                 :            : #define LEAP_RESPONSE_LEN 24
      20                 :            : #define LEAP_KEY_LEN 16
      21                 :            : 
      22                 :            : 
      23                 :            : struct eap_leap_data {
      24                 :            :         enum {
      25                 :            :                 LEAP_WAIT_CHALLENGE,
      26                 :            :                 LEAP_WAIT_SUCCESS,
      27                 :            :                 LEAP_WAIT_RESPONSE,
      28                 :            :                 LEAP_DONE
      29                 :            :         } state;
      30                 :            : 
      31                 :            :         u8 peer_challenge[LEAP_CHALLENGE_LEN];
      32                 :            :         u8 peer_response[LEAP_RESPONSE_LEN];
      33                 :            : 
      34                 :            :         u8 ap_challenge[LEAP_CHALLENGE_LEN];
      35                 :            :         u8 ap_response[LEAP_RESPONSE_LEN];
      36                 :            : };
      37                 :            : 
      38                 :            : 
      39                 :          0 : static void * eap_leap_init(struct eap_sm *sm)
      40                 :            : {
      41                 :            :         struct eap_leap_data *data;
      42                 :            : 
      43                 :          0 :         data = os_zalloc(sizeof(*data));
      44         [ #  # ]:          0 :         if (data == NULL)
      45                 :          0 :                 return NULL;
      46                 :          0 :         data->state = LEAP_WAIT_CHALLENGE;
      47                 :            : 
      48                 :          0 :         sm->leap_done = FALSE;
      49                 :          0 :         return data;
      50                 :            : }
      51                 :            : 
      52                 :            : 
      53                 :          0 : static void eap_leap_deinit(struct eap_sm *sm, void *priv)
      54                 :            : {
      55                 :          0 :         os_free(priv);
      56                 :          0 : }
      57                 :            : 
      58                 :            : 
      59                 :          0 : static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
      60                 :            :                                                 struct eap_method_ret *ret,
      61                 :            :                                                 const struct wpabuf *reqData)
      62                 :            : {
      63                 :          0 :         struct eap_leap_data *data = priv;
      64                 :            :         struct wpabuf *resp;
      65                 :            :         const u8 *pos, *challenge, *identity, *password;
      66                 :            :         u8 challenge_len, *rpos;
      67                 :            :         size_t identity_len, password_len, len;
      68                 :            :         int pwhash;
      69                 :            : 
      70                 :          0 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
      71                 :            : 
      72                 :          0 :         identity = eap_get_config_identity(sm, &identity_len);
      73                 :          0 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
      74 [ #  # ][ #  # ]:          0 :         if (identity == NULL || password == NULL)
      75                 :          0 :                 return NULL;
      76                 :            : 
      77                 :          0 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
      78 [ #  # ][ #  # ]:          0 :         if (pos == NULL || len < 3) {
      79                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
      80                 :          0 :                 ret->ignore = TRUE;
      81                 :          0 :                 return NULL;
      82                 :            :         }
      83                 :            : 
      84         [ #  # ]:          0 :         if (*pos != LEAP_VERSION) {
      85                 :          0 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
      86                 :          0 :                            "%d", *pos);
      87                 :          0 :                 ret->ignore = TRUE;
      88                 :          0 :                 return NULL;
      89                 :            :         }
      90                 :          0 :         pos++;
      91                 :            : 
      92                 :          0 :         pos++; /* skip unused byte */
      93                 :            : 
      94                 :          0 :         challenge_len = *pos++;
      95 [ #  # ][ #  # ]:          0 :         if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
      96                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
      97                 :            :                            "(challenge_len=%d reqDataLen=%lu)",
      98                 :            :                            challenge_len, (unsigned long) wpabuf_len(reqData));
      99                 :          0 :                 ret->ignore = TRUE;
     100                 :          0 :                 return NULL;
     101                 :            :         }
     102                 :          0 :         challenge = pos;
     103                 :          0 :         os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
     104                 :          0 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
     105                 :            :                     challenge, LEAP_CHALLENGE_LEN);
     106                 :            : 
     107                 :          0 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
     108                 :            : 
     109                 :          0 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
     110                 :            :                              3 + LEAP_RESPONSE_LEN + identity_len,
     111                 :          0 :                              EAP_CODE_RESPONSE, eap_get_id(reqData));
     112         [ #  # ]:          0 :         if (resp == NULL)
     113                 :          0 :                 return NULL;
     114                 :          0 :         wpabuf_put_u8(resp, LEAP_VERSION);
     115                 :          0 :         wpabuf_put_u8(resp, 0); /* unused */
     116                 :          0 :         wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
     117                 :          0 :         rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
     118         [ #  # ]:          0 :         if (pwhash)
     119                 :          0 :                 challenge_response(challenge, password, rpos);
     120                 :            :         else
     121                 :          0 :                 nt_challenge_response(challenge, password, password_len, rpos);
     122                 :          0 :         os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
     123                 :          0 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
     124                 :            :                     rpos, LEAP_RESPONSE_LEN);
     125                 :          0 :         wpabuf_put_data(resp, identity, identity_len);
     126                 :            : 
     127                 :          0 :         data->state = LEAP_WAIT_SUCCESS;
     128                 :            : 
     129                 :          0 :         return resp;
     130                 :            : }
     131                 :            : 
     132                 :            : 
     133                 :          0 : static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
     134                 :            :                                                 struct eap_method_ret *ret,
     135                 :            :                                                 const struct wpabuf *reqData)
     136                 :            : {
     137                 :          0 :         struct eap_leap_data *data = priv;
     138                 :            :         struct wpabuf *resp;
     139                 :            :         u8 *pos;
     140                 :            :         const u8 *identity;
     141                 :            :         size_t identity_len;
     142                 :            : 
     143                 :          0 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
     144                 :            : 
     145                 :          0 :         identity = eap_get_config_identity(sm, &identity_len);
     146         [ #  # ]:          0 :         if (identity == NULL)
     147                 :          0 :                 return NULL;
     148                 :            : 
     149         [ #  # ]:          0 :         if (data->state != LEAP_WAIT_SUCCESS) {
     150                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
     151                 :          0 :                            "unexpected state (%d) - ignored", data->state);
     152                 :          0 :                 ret->ignore = TRUE;
     153                 :          0 :                 return NULL;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
     157                 :            :                              3 + LEAP_CHALLENGE_LEN + identity_len,
     158                 :          0 :                              EAP_CODE_REQUEST, eap_get_id(reqData));
     159         [ #  # ]:          0 :         if (resp == NULL)
     160                 :          0 :                 return NULL;
     161                 :          0 :         wpabuf_put_u8(resp, LEAP_VERSION);
     162                 :          0 :         wpabuf_put_u8(resp, 0); /* unused */
     163                 :          0 :         wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
     164                 :          0 :         pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
     165         [ #  # ]:          0 :         if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) {
     166                 :          0 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
     167                 :            :                            "for challenge");
     168                 :          0 :                 wpabuf_free(resp);
     169                 :          0 :                 ret->ignore = TRUE;
     170                 :          0 :                 return NULL;
     171                 :            :         }
     172                 :          0 :         os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
     173                 :          0 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
     174                 :            :                     LEAP_CHALLENGE_LEN);
     175                 :          0 :         wpabuf_put_data(resp, identity, identity_len);
     176                 :            : 
     177                 :          0 :         data->state = LEAP_WAIT_RESPONSE;
     178                 :            : 
     179                 :          0 :         return resp;
     180                 :            : }
     181                 :            : 
     182                 :            : 
     183                 :          0 : static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
     184                 :            :                                                  struct eap_method_ret *ret,
     185                 :            :                                                  const struct wpabuf *reqData)
     186                 :            : {
     187                 :          0 :         struct eap_leap_data *data = priv;
     188                 :            :         const u8 *pos, *password;
     189                 :            :         u8 response_len, pw_hash[16], pw_hash_hash[16],
     190                 :            :                 expected[LEAP_RESPONSE_LEN];
     191                 :            :         size_t password_len, len;
     192                 :            :         int pwhash;
     193                 :            : 
     194                 :          0 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
     195                 :            : 
     196                 :          0 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
     197         [ #  # ]:          0 :         if (password == NULL)
     198                 :          0 :                 return NULL;
     199                 :            : 
     200                 :          0 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
     201 [ #  # ][ #  # ]:          0 :         if (pos == NULL || len < 3) {
     202                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
     203                 :          0 :                 ret->ignore = TRUE;
     204                 :          0 :                 return NULL;
     205                 :            :         }
     206                 :            : 
     207         [ #  # ]:          0 :         if (*pos != LEAP_VERSION) {
     208                 :          0 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
     209                 :          0 :                            "%d", *pos);
     210                 :          0 :                 ret->ignore = TRUE;
     211                 :          0 :                 return NULL;
     212                 :            :         }
     213                 :          0 :         pos++;
     214                 :            : 
     215                 :          0 :         pos++; /* skip unused byte */
     216                 :            : 
     217                 :          0 :         response_len = *pos++;
     218 [ #  # ][ #  # ]:          0 :         if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
     219                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
     220                 :            :                            "(response_len=%d reqDataLen=%lu)",
     221                 :            :                            response_len, (unsigned long) wpabuf_len(reqData));
     222                 :          0 :                 ret->ignore = TRUE;
     223                 :          0 :                 return NULL;
     224                 :            :         }
     225                 :            : 
     226                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
     227                 :            :                     pos, LEAP_RESPONSE_LEN);
     228                 :          0 :         os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
     229                 :            : 
     230         [ #  # ]:          0 :         if (pwhash) {
     231         [ #  # ]:          0 :                 if (hash_nt_password_hash(password, pw_hash_hash)) {
     232                 :          0 :                         ret->ignore = TRUE;
     233                 :          0 :                         return NULL;
     234                 :            :                 }
     235                 :            :         } else {
     236   [ #  #  #  # ]:          0 :                 if (nt_password_hash(password, password_len, pw_hash) ||
     237                 :          0 :                     hash_nt_password_hash(pw_hash, pw_hash_hash)) {
     238                 :          0 :                         ret->ignore = TRUE;
     239                 :          0 :                         return NULL;
     240                 :            :                 }
     241                 :            :         }
     242                 :          0 :         challenge_response(data->ap_challenge, pw_hash_hash, expected);
     243                 :            : 
     244                 :          0 :         ret->methodState = METHOD_DONE;
     245                 :          0 :         ret->allowNotifications = FALSE;
     246                 :            : 
     247         [ #  # ]:          0 :         if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
     248                 :          0 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
     249                 :            :                            "response - authentication failed");
     250                 :          0 :                 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
     251                 :            :                             expected, LEAP_RESPONSE_LEN);
     252                 :          0 :                 ret->decision = DECISION_FAIL;
     253                 :          0 :                 return NULL;
     254                 :            :         }
     255                 :            : 
     256                 :          0 :         ret->decision = DECISION_UNCOND_SUCC;
     257                 :            : 
     258                 :            :         /* LEAP is somewhat odd method since it sends EAP-Success in the middle
     259                 :            :          * of the authentication. Use special variable to transit EAP state
     260                 :            :          * machine to SUCCESS state. */
     261                 :          0 :         sm->leap_done = TRUE;
     262                 :          0 :         data->state = LEAP_DONE;
     263                 :            : 
     264                 :            :         /* No more authentication messages expected; AP will send EAPOL-Key
     265                 :            :          * frames if encryption is enabled. */
     266                 :          0 :         return NULL;
     267                 :            : }
     268                 :            : 
     269                 :            : 
     270                 :          0 : static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
     271                 :            :                                         struct eap_method_ret *ret,
     272                 :            :                                         const struct wpabuf *reqData)
     273                 :            : {
     274                 :            :         const struct eap_hdr *eap;
     275                 :            :         size_t password_len;
     276                 :            :         const u8 *password;
     277                 :            : 
     278                 :          0 :         password = eap_get_config_password(sm, &password_len);
     279         [ #  # ]:          0 :         if (password == NULL) {
     280                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
     281                 :          0 :                 eap_sm_request_password(sm);
     282                 :          0 :                 ret->ignore = TRUE;
     283                 :          0 :                 return NULL;
     284                 :            :         }
     285                 :            : 
     286                 :            :         /*
     287                 :            :          * LEAP needs to be able to handle EAP-Success frame which does not
     288                 :            :          * include Type field. Consequently, eap_hdr_validate() cannot be used
     289                 :            :          * here. This validation will be done separately for EAP-Request and
     290                 :            :          * EAP-Response frames.
     291                 :            :          */
     292                 :          0 :         eap = wpabuf_head(reqData);
     293   [ #  #  #  # ]:          0 :         if (wpabuf_len(reqData) < sizeof(*eap) ||
     294                 :          0 :             be_to_host16(eap->length) > wpabuf_len(reqData)) {
     295                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
     296                 :          0 :                 ret->ignore = TRUE;
     297                 :          0 :                 return NULL;
     298                 :            :         }
     299                 :            : 
     300                 :          0 :         ret->ignore = FALSE;
     301                 :          0 :         ret->allowNotifications = TRUE;
     302                 :          0 :         ret->methodState = METHOD_MAY_CONT;
     303                 :          0 :         ret->decision = DECISION_FAIL;
     304                 :            : 
     305                 :          0 :         sm->leap_done = FALSE;
     306                 :            : 
     307   [ #  #  #  # ]:          0 :         switch (eap->code) {
     308                 :            :         case EAP_CODE_REQUEST:
     309                 :          0 :                 return eap_leap_process_request(sm, priv, ret, reqData);
     310                 :            :         case EAP_CODE_SUCCESS:
     311                 :          0 :                 return eap_leap_process_success(sm, priv, ret, reqData);
     312                 :            :         case EAP_CODE_RESPONSE:
     313                 :          0 :                 return eap_leap_process_response(sm, priv, ret, reqData);
     314                 :            :         default:
     315                 :          0 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
     316                 :          0 :                            "ignored", eap->code);
     317                 :          0 :                 ret->ignore = TRUE;
     318                 :          0 :                 return NULL;
     319                 :            :         }
     320                 :            : }
     321                 :            : 
     322                 :            : 
     323                 :          0 : static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
     324                 :            : {
     325                 :          0 :         struct eap_leap_data *data = priv;
     326                 :          0 :         return data->state == LEAP_DONE;
     327                 :            : }
     328                 :            : 
     329                 :            : 
     330                 :          0 : static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
     331                 :            : {
     332                 :          0 :         struct eap_leap_data *data = priv;
     333                 :            :         u8 *key, pw_hash_hash[16], pw_hash[16];
     334                 :            :         const u8 *addr[5], *password;
     335                 :            :         size_t elen[5], password_len;
     336                 :            :         int pwhash;
     337                 :            : 
     338         [ #  # ]:          0 :         if (data->state != LEAP_DONE)
     339                 :          0 :                 return NULL;
     340                 :            : 
     341                 :          0 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
     342         [ #  # ]:          0 :         if (password == NULL)
     343                 :          0 :                 return NULL;
     344                 :            : 
     345                 :          0 :         key = os_malloc(LEAP_KEY_LEN);
     346         [ #  # ]:          0 :         if (key == NULL)
     347                 :          0 :                 return NULL;
     348                 :            : 
     349         [ #  # ]:          0 :         if (pwhash) {
     350         [ #  # ]:          0 :                 if (hash_nt_password_hash(password, pw_hash_hash)) {
     351                 :          0 :                         os_free(key);
     352                 :          0 :                         return NULL;
     353                 :            :                 }
     354                 :            :         } else {
     355   [ #  #  #  # ]:          0 :                 if (nt_password_hash(password, password_len, pw_hash) ||
     356                 :          0 :                     hash_nt_password_hash(pw_hash, pw_hash_hash)) {
     357                 :          0 :                         os_free(key);
     358                 :          0 :                         return NULL;
     359                 :            :                 }
     360                 :            :         }
     361                 :          0 :         wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
     362                 :            :                         pw_hash_hash, 16);
     363                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
     364                 :          0 :                     data->peer_challenge, LEAP_CHALLENGE_LEN);
     365                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
     366                 :          0 :                     data->peer_response, LEAP_RESPONSE_LEN);
     367                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
     368                 :          0 :                     data->ap_challenge, LEAP_CHALLENGE_LEN);
     369                 :          0 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
     370                 :          0 :                     data->ap_response, LEAP_RESPONSE_LEN);
     371                 :            : 
     372                 :          0 :         addr[0] = pw_hash_hash;
     373                 :          0 :         elen[0] = 16;
     374                 :          0 :         addr[1] = data->ap_challenge;
     375                 :          0 :         elen[1] = LEAP_CHALLENGE_LEN;
     376                 :          0 :         addr[2] = data->ap_response;
     377                 :          0 :         elen[2] = LEAP_RESPONSE_LEN;
     378                 :          0 :         addr[3] = data->peer_challenge;
     379                 :          0 :         elen[3] = LEAP_CHALLENGE_LEN;
     380                 :          0 :         addr[4] = data->peer_response;
     381                 :          0 :         elen[4] = LEAP_RESPONSE_LEN;
     382                 :          0 :         md5_vector(5, addr, elen, key);
     383                 :          0 :         wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
     384                 :          0 :         *len = LEAP_KEY_LEN;
     385                 :            : 
     386                 :          0 :         return key;
     387                 :            : }
     388                 :            : 
     389                 :            : 
     390                 :          4 : int eap_peer_leap_register(void)
     391                 :            : {
     392                 :            :         struct eap_method *eap;
     393                 :            :         int ret;
     394                 :            : 
     395                 :          4 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     396                 :            :                                     EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
     397         [ -  + ]:          4 :         if (eap == NULL)
     398                 :          0 :                 return -1;
     399                 :            : 
     400                 :          4 :         eap->init = eap_leap_init;
     401                 :          4 :         eap->deinit = eap_leap_deinit;
     402                 :          4 :         eap->process = eap_leap_process;
     403                 :          4 :         eap->isKeyAvailable = eap_leap_isKeyAvailable;
     404                 :          4 :         eap->getKey = eap_leap_getKey;
     405                 :            : 
     406                 :          4 :         ret = eap_peer_method_register(eap);
     407         [ -  + ]:          4 :         if (ret)
     408                 :          0 :                 eap_peer_method_free(eap);
     409                 :          4 :         return ret;
     410                 :            : }

Generated by: LCOV version 1.9