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 1443382998 Lines: 172 213 80.8 %
Date: 2015-09-27 Functions: 9 9 100.0 %

          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          12 : static void * eap_leap_init(struct eap_sm *sm)
      40             : {
      41             :         struct eap_leap_data *data;
      42             : 
      43          12 :         data = os_zalloc(sizeof(*data));
      44          12 :         if (data == NULL)
      45           0 :                 return NULL;
      46          12 :         data->state = LEAP_WAIT_CHALLENGE;
      47             : 
      48          12 :         sm->leap_done = FALSE;
      49          12 :         return data;
      50             : }
      51             : 
      52             : 
      53          12 : static void eap_leap_deinit(struct eap_sm *sm, void *priv)
      54             : {
      55          12 :         os_free(priv);
      56          12 : }
      57             : 
      58             : 
      59          12 : 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          12 :         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          12 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
      71             : 
      72          12 :         identity = eap_get_config_identity(sm, &identity_len);
      73          12 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
      74          12 :         if (identity == NULL || password == NULL)
      75           0 :                 return NULL;
      76             : 
      77          12 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
      78          12 :         if (pos == NULL || len < 3) {
      79           1 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
      80           1 :                 ret->ignore = TRUE;
      81           1 :                 return NULL;
      82             :         }
      83             : 
      84          11 :         if (*pos != LEAP_VERSION) {
      85           1 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
      86           1 :                            "%d", *pos);
      87           1 :                 ret->ignore = TRUE;
      88           1 :                 return NULL;
      89             :         }
      90          10 :         pos++;
      91             : 
      92          10 :         pos++; /* skip unused byte */
      93             : 
      94          10 :         challenge_len = *pos++;
      95          10 :         if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
      96           2 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
      97             :                            "(challenge_len=%d reqDataLen=%lu)",
      98             :                            challenge_len, (unsigned long) wpabuf_len(reqData));
      99           2 :                 ret->ignore = TRUE;
     100           2 :                 return NULL;
     101             :         }
     102           8 :         challenge = pos;
     103           8 :         os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
     104           8 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
     105             :                     challenge, LEAP_CHALLENGE_LEN);
     106             : 
     107           8 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
     108             : 
     109           8 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
     110             :                              3 + LEAP_RESPONSE_LEN + identity_len,
     111           8 :                              EAP_CODE_RESPONSE, eap_get_id(reqData));
     112           8 :         if (resp == NULL)
     113           0 :                 return NULL;
     114           8 :         wpabuf_put_u8(resp, LEAP_VERSION);
     115           8 :         wpabuf_put_u8(resp, 0); /* unused */
     116           8 :         wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
     117           8 :         rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
     118           8 :         if (pwhash)
     119           0 :                 challenge_response(challenge, password, rpos);
     120             :         else
     121           8 :                 nt_challenge_response(challenge, password, password_len, rpos);
     122           8 :         os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
     123           8 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
     124             :                     rpos, LEAP_RESPONSE_LEN);
     125           8 :         wpabuf_put_data(resp, identity, identity_len);
     126             : 
     127           8 :         data->state = LEAP_WAIT_SUCCESS;
     128             : 
     129           8 :         return resp;
     130             : }
     131             : 
     132             : 
     133           1 : 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           1 :         struct eap_leap_data *data = priv;
     138             :         struct wpabuf *resp;
     139             :         u8 *pos;
     140             :         const u8 *identity;
     141             :         size_t identity_len;
     142             : 
     143           1 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
     144             : 
     145           1 :         identity = eap_get_config_identity(sm, &identity_len);
     146           1 :         if (identity == NULL)
     147           0 :                 return NULL;
     148             : 
     149           1 :         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           1 :         resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
     157             :                              3 + LEAP_CHALLENGE_LEN + identity_len,
     158           1 :                              EAP_CODE_REQUEST, eap_get_id(reqData));
     159           1 :         if (resp == NULL)
     160           0 :                 return NULL;
     161           1 :         wpabuf_put_u8(resp, LEAP_VERSION);
     162           1 :         wpabuf_put_u8(resp, 0); /* unused */
     163           1 :         wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
     164           1 :         pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
     165           1 :         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           1 :         os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
     173           1 :         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
     174             :                     LEAP_CHALLENGE_LEN);
     175           1 :         wpabuf_put_data(resp, identity, identity_len);
     176             : 
     177           1 :         data->state = LEAP_WAIT_RESPONSE;
     178             : 
     179           1 :         return resp;
     180             : }
     181             : 
     182             : 
     183           6 : 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           6 :         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           6 :         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
     195             : 
     196           6 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
     197           6 :         if (password == NULL)
     198           0 :                 return NULL;
     199             : 
     200           6 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
     201           6 :         if (pos == NULL || len < 3) {
     202           1 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
     203           1 :                 ret->ignore = TRUE;
     204           1 :                 return NULL;
     205             :         }
     206             : 
     207           5 :         if (*pos != LEAP_VERSION) {
     208           1 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
     209           1 :                            "%d", *pos);
     210           1 :                 ret->ignore = TRUE;
     211           1 :                 return NULL;
     212             :         }
     213           4 :         pos++;
     214             : 
     215           4 :         pos++; /* skip unused byte */
     216             : 
     217           4 :         response_len = *pos++;
     218           4 :         if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
     219           2 :                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
     220             :                            "(response_len=%d reqDataLen=%lu)",
     221             :                            response_len, (unsigned long) wpabuf_len(reqData));
     222           2 :                 ret->ignore = TRUE;
     223           2 :                 return NULL;
     224             :         }
     225             : 
     226           2 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
     227             :                     pos, LEAP_RESPONSE_LEN);
     228           2 :         os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
     229             : 
     230           2 :         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           4 :                 if (nt_password_hash(password, password_len, pw_hash) ||
     237           2 :                     hash_nt_password_hash(pw_hash, pw_hash_hash)) {
     238           0 :                         ret->ignore = TRUE;
     239           0 :                         return NULL;
     240             :                 }
     241             :         }
     242           2 :         challenge_response(data->ap_challenge, pw_hash_hash, expected);
     243             : 
     244           2 :         ret->methodState = METHOD_DONE;
     245           2 :         ret->allowNotifications = FALSE;
     246             : 
     247           2 :         if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
     248           1 :                 wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
     249             :                            "response - authentication failed");
     250           1 :                 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
     251             :                             expected, LEAP_RESPONSE_LEN);
     252           1 :                 ret->decision = DECISION_FAIL;
     253           1 :                 return NULL;
     254             :         }
     255             : 
     256           1 :         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           1 :         sm->leap_done = TRUE;
     262           1 :         data->state = LEAP_DONE;
     263             : 
     264             :         /* No more authentication messages expected; AP will send EAPOL-Key
     265             :          * frames if encryption is enabled. */
     266           1 :         return NULL;
     267             : }
     268             : 
     269             : 
     270          19 : 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          19 :         password = eap_get_config_password(sm, &password_len);
     279          19 :         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          19 :         eap = wpabuf_head(reqData);
     293          38 :         if (wpabuf_len(reqData) < sizeof(*eap) ||
     294          19 :             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          19 :         ret->ignore = FALSE;
     301          19 :         ret->allowNotifications = TRUE;
     302          19 :         ret->methodState = METHOD_MAY_CONT;
     303          19 :         ret->decision = DECISION_FAIL;
     304             : 
     305          19 :         sm->leap_done = FALSE;
     306             : 
     307          19 :         switch (eap->code) {
     308             :         case EAP_CODE_REQUEST:
     309          12 :                 return eap_leap_process_request(sm, priv, ret, reqData);
     310             :         case EAP_CODE_SUCCESS:
     311           1 :                 return eap_leap_process_success(sm, priv, ret, reqData);
     312             :         case EAP_CODE_RESPONSE:
     313           6 :                 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          11 : static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
     324             : {
     325          11 :         struct eap_leap_data *data = priv;
     326          11 :         return data->state == LEAP_DONE;
     327             : }
     328             : 
     329             : 
     330           1 : static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
     331             : {
     332           1 :         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           1 :         if (data->state != LEAP_DONE)
     339           0 :                 return NULL;
     340             : 
     341           1 :         password = eap_get_config_password2(sm, &password_len, &pwhash);
     342           1 :         if (password == NULL)
     343           0 :                 return NULL;
     344             : 
     345           1 :         key = os_malloc(LEAP_KEY_LEN);
     346           1 :         if (key == NULL)
     347           0 :                 return NULL;
     348             : 
     349           1 :         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           2 :                 if (nt_password_hash(password, password_len, pw_hash) ||
     356           1 :                     hash_nt_password_hash(pw_hash, pw_hash_hash)) {
     357           0 :                         os_free(key);
     358           0 :                         return NULL;
     359             :                 }
     360             :         }
     361           1 :         wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
     362             :                         pw_hash_hash, 16);
     363           1 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
     364           1 :                     data->peer_challenge, LEAP_CHALLENGE_LEN);
     365           1 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
     366           1 :                     data->peer_response, LEAP_RESPONSE_LEN);
     367           1 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
     368           1 :                     data->ap_challenge, LEAP_CHALLENGE_LEN);
     369           1 :         wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
     370           1 :                     data->ap_response, LEAP_RESPONSE_LEN);
     371             : 
     372           1 :         addr[0] = pw_hash_hash;
     373           1 :         elen[0] = 16;
     374           1 :         addr[1] = data->ap_challenge;
     375           1 :         elen[1] = LEAP_CHALLENGE_LEN;
     376           1 :         addr[2] = data->ap_response;
     377           1 :         elen[2] = LEAP_RESPONSE_LEN;
     378           1 :         addr[3] = data->peer_challenge;
     379           1 :         elen[3] = LEAP_CHALLENGE_LEN;
     380           1 :         addr[4] = data->peer_response;
     381           1 :         elen[4] = LEAP_RESPONSE_LEN;
     382           1 :         md5_vector(5, addr, elen, key);
     383           1 :         wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
     384           1 :         *len = LEAP_KEY_LEN;
     385             : 
     386           1 :         os_memset(pw_hash, 0, sizeof(pw_hash));
     387           1 :         os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash));
     388             : 
     389           1 :         return key;
     390             : }
     391             : 
     392             : 
     393          49 : int eap_peer_leap_register(void)
     394             : {
     395             :         struct eap_method *eap;
     396             :         int ret;
     397             : 
     398          49 :         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
     399             :                                     EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
     400          49 :         if (eap == NULL)
     401           0 :                 return -1;
     402             : 
     403          49 :         eap->init = eap_leap_init;
     404          49 :         eap->deinit = eap_leap_deinit;
     405          49 :         eap->process = eap_leap_process;
     406          49 :         eap->isKeyAvailable = eap_leap_isKeyAvailable;
     407          49 :         eap->getKey = eap_leap_getKey;
     408             : 
     409          49 :         ret = eap_peer_method_register(eap);
     410          49 :         if (ret)
     411           0 :                 eap_peer_method_free(eap);
     412          49 :         return ret;
     413             : }

Generated by: LCOV version 1.10