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 1401264779 Lines: 11 211 5.2 %
Date: 2014-05-28 Functions: 1 9 11.1 %

          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.10