$search
00001 /* 00002 * EAP peer method: LEAP 00003 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "crypto/ms_funcs.h" 00019 #include "crypto/crypto.h" 00020 #include "eap_i.h" 00021 00022 #define LEAP_VERSION 1 00023 #define LEAP_CHALLENGE_LEN 8 00024 #define LEAP_RESPONSE_LEN 24 00025 #define LEAP_KEY_LEN 16 00026 00027 00028 struct eap_leap_data { 00029 enum { 00030 LEAP_WAIT_CHALLENGE, 00031 LEAP_WAIT_SUCCESS, 00032 LEAP_WAIT_RESPONSE, 00033 LEAP_DONE 00034 } state; 00035 00036 u8 peer_challenge[LEAP_CHALLENGE_LEN]; 00037 u8 peer_response[LEAP_RESPONSE_LEN]; 00038 00039 u8 ap_challenge[LEAP_CHALLENGE_LEN]; 00040 u8 ap_response[LEAP_RESPONSE_LEN]; 00041 }; 00042 00043 00044 static void * eap_leap_init(struct eap_sm *sm) 00045 { 00046 struct eap_leap_data *data; 00047 00048 data = os_zalloc(sizeof(*data)); 00049 if (data == NULL) 00050 return NULL; 00051 data->state = LEAP_WAIT_CHALLENGE; 00052 00053 sm->leap_done = FALSE; 00054 return data; 00055 } 00056 00057 00058 static void eap_leap_deinit(struct eap_sm *sm, void *priv) 00059 { 00060 os_free(priv); 00061 } 00062 00063 00064 static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, 00065 struct eap_method_ret *ret, 00066 const struct wpabuf *reqData) 00067 { 00068 struct eap_leap_data *data = priv; 00069 struct wpabuf *resp; 00070 const u8 *pos, *challenge, *identity, *password; 00071 u8 challenge_len, *rpos; 00072 size_t identity_len, password_len, len; 00073 int pwhash; 00074 00075 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); 00076 00077 identity = eap_get_config_identity(sm, &identity_len); 00078 password = eap_get_config_password2(sm, &password_len, &pwhash); 00079 if (identity == NULL || password == NULL) 00080 return NULL; 00081 00082 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 00083 if (pos == NULL || len < 3) { 00084 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); 00085 ret->ignore = TRUE; 00086 return NULL; 00087 } 00088 00089 if (*pos != LEAP_VERSION) { 00090 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 00091 "%d", *pos); 00092 ret->ignore = TRUE; 00093 return NULL; 00094 } 00095 pos++; 00096 00097 pos++; /* skip unused byte */ 00098 00099 challenge_len = *pos++; 00100 if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { 00101 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " 00102 "(challenge_len=%d reqDataLen=%lu)", 00103 challenge_len, (unsigned long) wpabuf_len(reqData)); 00104 ret->ignore = TRUE; 00105 return NULL; 00106 } 00107 challenge = pos; 00108 os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); 00109 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", 00110 challenge, LEAP_CHALLENGE_LEN); 00111 00112 wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); 00113 00114 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 00115 3 + LEAP_RESPONSE_LEN + identity_len, 00116 EAP_CODE_RESPONSE, eap_get_id(reqData)); 00117 if (resp == NULL) 00118 return NULL; 00119 wpabuf_put_u8(resp, LEAP_VERSION); 00120 wpabuf_put_u8(resp, 0); /* unused */ 00121 wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); 00122 rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); 00123 if (pwhash) 00124 challenge_response(challenge, password, rpos); 00125 else 00126 nt_challenge_response(challenge, password, password_len, rpos); 00127 os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); 00128 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", 00129 rpos, LEAP_RESPONSE_LEN); 00130 wpabuf_put_data(resp, identity, identity_len); 00131 00132 data->state = LEAP_WAIT_SUCCESS; 00133 00134 return resp; 00135 } 00136 00137 00138 static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv, 00139 struct eap_method_ret *ret, 00140 const struct wpabuf *reqData) 00141 { 00142 struct eap_leap_data *data = priv; 00143 struct wpabuf *resp; 00144 u8 *pos; 00145 const u8 *identity; 00146 size_t identity_len; 00147 00148 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success"); 00149 00150 identity = eap_get_config_identity(sm, &identity_len); 00151 if (identity == NULL) 00152 return NULL; 00153 00154 if (data->state != LEAP_WAIT_SUCCESS) { 00155 wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in " 00156 "unexpected state (%d) - ignored", data->state); 00157 ret->ignore = TRUE; 00158 return NULL; 00159 } 00160 00161 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 00162 3 + LEAP_CHALLENGE_LEN + identity_len, 00163 EAP_CODE_REQUEST, eap_get_id(reqData)); 00164 if (resp == NULL) 00165 return NULL; 00166 wpabuf_put_u8(resp, LEAP_VERSION); 00167 wpabuf_put_u8(resp, 0); /* unused */ 00168 wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN); 00169 pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN); 00170 if (os_get_random(pos, LEAP_CHALLENGE_LEN)) { 00171 wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data " 00172 "for challenge"); 00173 wpabuf_free(resp); 00174 ret->ignore = TRUE; 00175 return NULL; 00176 } 00177 os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN); 00178 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos, 00179 LEAP_CHALLENGE_LEN); 00180 wpabuf_put_data(resp, identity, identity_len); 00181 00182 data->state = LEAP_WAIT_RESPONSE; 00183 00184 return resp; 00185 } 00186 00187 00188 static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, 00189 struct eap_method_ret *ret, 00190 const struct wpabuf *reqData) 00191 { 00192 struct eap_leap_data *data = priv; 00193 const u8 *pos, *password; 00194 u8 response_len, pw_hash[16], pw_hash_hash[16], 00195 expected[LEAP_RESPONSE_LEN]; 00196 size_t password_len, len; 00197 int pwhash; 00198 00199 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); 00200 00201 password = eap_get_config_password2(sm, &password_len, &pwhash); 00202 if (password == NULL) 00203 return NULL; 00204 00205 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 00206 if (pos == NULL || len < 3) { 00207 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); 00208 ret->ignore = TRUE; 00209 return NULL; 00210 } 00211 00212 if (*pos != LEAP_VERSION) { 00213 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 00214 "%d", *pos); 00215 ret->ignore = TRUE; 00216 return NULL; 00217 } 00218 pos++; 00219 00220 pos++; /* skip unused byte */ 00221 00222 response_len = *pos++; 00223 if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { 00224 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " 00225 "(response_len=%d reqDataLen=%lu)", 00226 response_len, (unsigned long) wpabuf_len(reqData)); 00227 ret->ignore = TRUE; 00228 return NULL; 00229 } 00230 00231 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", 00232 pos, LEAP_RESPONSE_LEN); 00233 os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); 00234 00235 if (pwhash) { 00236 if (hash_nt_password_hash(password, pw_hash_hash)) { 00237 ret->ignore = TRUE; 00238 return NULL; 00239 } 00240 } else { 00241 if (nt_password_hash(password, password_len, pw_hash) || 00242 hash_nt_password_hash(pw_hash, pw_hash_hash)) { 00243 ret->ignore = TRUE; 00244 return NULL; 00245 } 00246 } 00247 challenge_response(data->ap_challenge, pw_hash_hash, expected); 00248 00249 ret->methodState = METHOD_DONE; 00250 ret->allowNotifications = FALSE; 00251 00252 if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { 00253 wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " 00254 "response - authentication failed"); 00255 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", 00256 expected, LEAP_RESPONSE_LEN); 00257 ret->decision = DECISION_FAIL; 00258 return NULL; 00259 } 00260 00261 ret->decision = DECISION_UNCOND_SUCC; 00262 00263 /* LEAP is somewhat odd method since it sends EAP-Success in the middle 00264 * of the authentication. Use special variable to transit EAP state 00265 * machine to SUCCESS state. */ 00266 sm->leap_done = TRUE; 00267 data->state = LEAP_DONE; 00268 00269 /* No more authentication messages expected; AP will send EAPOL-Key 00270 * frames if encryption is enabled. */ 00271 return NULL; 00272 } 00273 00274 00275 static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, 00276 struct eap_method_ret *ret, 00277 const struct wpabuf *reqData) 00278 { 00279 const struct eap_hdr *eap; 00280 size_t password_len; 00281 const u8 *password; 00282 00283 password = eap_get_config_password(sm, &password_len); 00284 if (password == NULL) { 00285 wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); 00286 eap_sm_request_password(sm); 00287 ret->ignore = TRUE; 00288 return NULL; 00289 } 00290 00291 /* 00292 * LEAP needs to be able to handle EAP-Success frame which does not 00293 * include Type field. Consequently, eap_hdr_validate() cannot be used 00294 * here. This validation will be done separately for EAP-Request and 00295 * EAP-Response frames. 00296 */ 00297 eap = wpabuf_head(reqData); 00298 if (wpabuf_len(reqData) < sizeof(*eap) || 00299 be_to_host16(eap->length) > wpabuf_len(reqData)) { 00300 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); 00301 ret->ignore = TRUE; 00302 return NULL; 00303 } 00304 00305 ret->ignore = FALSE; 00306 ret->allowNotifications = TRUE; 00307 ret->methodState = METHOD_MAY_CONT; 00308 ret->decision = DECISION_FAIL; 00309 00310 sm->leap_done = FALSE; 00311 00312 switch (eap->code) { 00313 case EAP_CODE_REQUEST: 00314 return eap_leap_process_request(sm, priv, ret, reqData); 00315 case EAP_CODE_SUCCESS: 00316 return eap_leap_process_success(sm, priv, ret, reqData); 00317 case EAP_CODE_RESPONSE: 00318 return eap_leap_process_response(sm, priv, ret, reqData); 00319 default: 00320 wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " 00321 "ignored", eap->code); 00322 ret->ignore = TRUE; 00323 return NULL; 00324 } 00325 } 00326 00327 00328 static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv) 00329 { 00330 struct eap_leap_data *data = priv; 00331 return data->state == LEAP_DONE; 00332 } 00333 00334 00335 static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) 00336 { 00337 struct eap_leap_data *data = priv; 00338 u8 *key, pw_hash_hash[16], pw_hash[16]; 00339 const u8 *addr[5], *password; 00340 size_t elen[5], password_len; 00341 int pwhash; 00342 00343 if (data->state != LEAP_DONE) 00344 return NULL; 00345 00346 password = eap_get_config_password2(sm, &password_len, &pwhash); 00347 if (password == NULL) 00348 return NULL; 00349 00350 key = os_malloc(LEAP_KEY_LEN); 00351 if (key == NULL) 00352 return NULL; 00353 00354 if (pwhash) { 00355 if (hash_nt_password_hash(password, pw_hash_hash)) { 00356 os_free(key); 00357 return NULL; 00358 } 00359 } else { 00360 if (nt_password_hash(password, password_len, pw_hash) || 00361 hash_nt_password_hash(pw_hash, pw_hash_hash)) { 00362 os_free(key); 00363 return NULL; 00364 } 00365 } 00366 wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", 00367 pw_hash_hash, 16); 00368 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", 00369 data->peer_challenge, LEAP_CHALLENGE_LEN); 00370 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", 00371 data->peer_response, LEAP_RESPONSE_LEN); 00372 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", 00373 data->ap_challenge, LEAP_CHALLENGE_LEN); 00374 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", 00375 data->ap_response, LEAP_RESPONSE_LEN); 00376 00377 addr[0] = pw_hash_hash; 00378 elen[0] = 16; 00379 addr[1] = data->ap_challenge; 00380 elen[1] = LEAP_CHALLENGE_LEN; 00381 addr[2] = data->ap_response; 00382 elen[2] = LEAP_RESPONSE_LEN; 00383 addr[3] = data->peer_challenge; 00384 elen[3] = LEAP_CHALLENGE_LEN; 00385 addr[4] = data->peer_response; 00386 elen[4] = LEAP_RESPONSE_LEN; 00387 md5_vector(5, addr, elen, key); 00388 wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); 00389 *len = LEAP_KEY_LEN; 00390 00391 return key; 00392 } 00393 00394 00395 int eap_peer_leap_register(void) 00396 { 00397 struct eap_method *eap; 00398 int ret; 00399 00400 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 00401 EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); 00402 if (eap == NULL) 00403 return -1; 00404 00405 eap->init = eap_leap_init; 00406 eap->deinit = eap_leap_deinit; 00407 eap->process = eap_leap_process; 00408 eap->isKeyAvailable = eap_leap_isKeyAvailable; 00409 eap->getKey = eap_leap_getKey; 00410 00411 ret = eap_peer_method_register(eap); 00412 if (ret) 00413 eap_peer_method_free(eap); 00414 return ret; 00415 }